package gbench.sandbox.matlib;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.databind.ObjectMapper;

import static gbench.common.matlib.MatlibCanvas.println;
import static gbench.common.matlib.algebra.lisp.IRecord.REC;
import static gbench.common.matlib.algebra.lisp.Tuple2.TUP2;
import static gbench.common.matlib.algebra.num4j.PmCm.L;
import static gbench.common.matlib.jdbc.Format.FT;
import static gbench.common.matlib.jdbc.SqlBuilder.select;
import static gbench.common.matlib.jdbc.index.Algorithm.KEY_VALUE;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Comparator;
import java.util.Date;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.function.Function;

import gbench.common.fs.XlsFile.SimpleExcel;
import gbench.common.matlib.algebra.AlgebraEngine;
import gbench.common.matlib.algebra.lisp.DFrame;
import gbench.common.matlib.algebra.lisp.IRecord;
import gbench.common.matlib.algebra.lisp.MyRecord;
import gbench.common.matlib.algebra.lisp.Tuple2;
import gbench.common.matlib.algebra.num4j.NVec;
import gbench.common.matlib.algebra.num4j.PmCm;
import gbench.common.matlib.algebra.num4j.Range;
import gbench.common.matlib.algebra.num4j.XVec;
import gbench.common.matlib.jdbc.JdbcApp;
import gbench.common.matlib.jdbc.index.TableSearchEngine;

/**
 * 
 * @author Administrator
 *
 */
public class JunitIRecord {

    /**
     * 
     */
    @Test
    public void foo() {
        final var aa = PmCm.A(1, 2);
        final var keys = "key1,key2,key3,key4".split(",");
        final var size = 6;
        final var rb = IRecord.rb(size, i -> FT("key$0", i + 1));
        final var root = PmCm.cph(PmCm.RPTA(size, aa)).map(rb::get).collect(IRecord.pvtclc(e -> e, keys));

        root.forEach((level, tup) -> {
            println(" | ".repeat(level) + tup);
        });
        println("json", root.json());
        println("1/2/1/1", root.pathget("1/2/1/1", e -> e));
        REC("name", "zhangsan", "sex", "man", "adress", REC("city", "shanghai", "street", "fahuazhen"))
                .forEach((level, tup) -> {
                    println(" | ".repeat(level) + tup);
                });
    }

    /**
     * 
     */
    @Test
    public void bar() {
        final var rb = IRecord.rb("a,b,c,d,e,f");
        final var a = rb.get(1, 2, 3);
        final var b = rb.get(1, 2, 3);

        println(a.equals(b), a == b, a.hashCode(), b.hashCode());

        // 时间类型数据的处理
        final var rb2 = rb.get(LocalDateTime.now(), // a
                LocalDateTime.now().toString(), // b
                LocalDate.now(), // c
                LocalTime.now(), // d
                "2019 1-1 5:4:4", // e
                "201911" // f
        );

        println("ldt", rb2.ldt("a"), rb2.ldt("b"), rb2.ldt("c"), rb2.ldt("d"), rb2.ldt("e"), rb2.ldt("f"));
        println("ldt2lng", rb2.lng("a"), new Date().getTime());
    }

    @Test
    public void quz() {
        final var jdbc = new JdbcApp("db2");

        final Function<String, Map<?, ?>> json_parser = json -> {
            final var objM = new ObjectMapper();
            try {
                final var map = objM.readValue(json, Map.class);
                return map;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        };

        jdbc.withTransaction(sess -> {
            final var sql = select("*").from("t_vertex").where("json_contains(Attributes,json_array('盘存'),'$.tags')");
            final var dfm = sess.sql2x(sql);
            final var rb = IRecord.rb(2, i -> FT("key$0", i));

            dfm.rowS().flatMap(e -> e.rec("Attributes", json_parser).llS2("summary", MyRecord::REC)).map(e -> {
                return e.add(rb.get(e.str("key").split("@")));
            }).collect(IRecord.grpclc2(e -> e.str("key").split("@")[1], e -> e, ee -> ee)).forEach((k, v) -> {
                println(k, v);
            });
        });
    }

    /**
     * 
     */
    @Test
    public void quz2() {

        final var db = "db";
        final var url = JdbcApp.mysql_url(db);
        final var srchEngine = new TableSearchEngine()
                .initialize(REC("url", url, "algorithms", TUP2(KEY_VALUE, "id,name:t_vertex")));
        final var decoder = srchEngine.getDecoder2(e -> e, "v0,v1:t_vertex");
        final var jdbc = new JdbcApp(db);
        jdbc.sqlquery(j -> j.sql2recordS("select * from t_edge limit 10").map(decoder).collect(Collectors.toList()))
                .forEach(e -> {
                    println(e);
                });

    }

    /**
     * 
     */
    @Test
    public void quz3() {
        final var rec = Stream.iterate(0, i -> i + 1).limit(10).collect(IRecord.rclc());

        println("齐次");
        rec.forEach((level, e) -> {
            println(IRecord.FT("$0 $1", " | ".repeat(level), e));
        });
        println("非齐次");
        rec.slidings(3, 1, false).forEach(e -> {
            println(e);
        });

        final var keysList = PmCm.A("9,1,2,3,8,7", "4,5, 6"); // 键表序列
        println("高阶record");
        final var hrec0 = rec.splitS(keysList).collect(IRecord.rclc()).arrayOf(IRecord.rb("A,B")::get); // 高阶record
        println(hrec0);

        final var hrec = rec.splitS(keysList).collect(IRecord.rclc2("A,B")); // 高阶record
        hrec.forEach((level, e) -> {
            println(IRecord.FT("$0 $1", " | ".repeat(level), e));
        });
        final var path = "B/4";
        println(path, hrec.pathdbl(path));

    }

    /**
     * 
     */
    @Test
    public void quz4() {
        final var rec = Stream.iterate(0, i -> i + 1).limit(10).collect(IRecord.rclc2(i -> "ABX" + i));
        println(rec);

        final var rec2 = Stream.iterate(0, i -> i + 1).limit(10).collect(IRecord.rclc2("a,b,c,d,e,f,g,h,i,j"));
        println(rec2);

        final var _rec2 = Stream.iterate(0, i -> i + 1).limit(10).collect(IRecord.rclc2("a,b,c"));
        println(_rec2);

        final var rec3 = Stream.iterate(0, i -> i + 1).limit(10).collect(IRecord.rclc2());
        println(rec3);
    }

    /**
     * 日期的演示
     */
    @Test
    public void date_demo() {
        final var now = LocalDate.now();
        final var end = LocalDate.now().plusYears(10);
        final var rb = IRecord.rb("no,time,end,value");
        final var ratio = 0.1;
        final var engine = new AlgebraEngine();
        final var node = engine.analyze("pow(1+ratio,duration)*value");
        final var dfm = Stream.iterate(0, i -> i + 1).limit(10).map(i -> rb.get(i, now.plusYears(i), end, 1000))
                .map(e -> e.add("duration",
                        e.arrayOf("time,end", IRecord::asLocalDate, (bb) -> bb[0].until(bb[1]).getYears())))
                .map(e -> e.add("ratio", ratio)).map(e -> e.add("amount", node.evaluate(e))).collect(DFrame.dfmclc);

        println(dfm.colS().collect(IRecord.rclc()));
        println("col3", dfm.col(3));
        println("col3 refresh", dfm.refresh().col(3));
        dfm.rowS().collect(IRecord.slidingclc(2, 1)).stream().map(e -> e.stream().collect(DFrame.dfmclc)).forEach(e -> {
            println(e);
        });
        println(dfm.sum("amount"));
        final var x = dfm.rowS().map(e -> e.filterNot("ratio,amount")).collect(DFrame.dfmclc);
        println(x);
        println("end", x.col("end", IRecord::asLocalDateTime).stream().collect(IRecord.rclc(e -> TUP2(e, 1)))
                .slidings(3, 1, false));
    }

    /**
     * record builder
     */
    @Test
    public void rb() {
        final var p = IRecord.rb("name,birth,marry") // 档案结构
                .get("zhangsan,19810713,20011023".split(",")) // 构建张三的数据记录
                .arrayOf("birth,marry", IRecord::asLocalDate, // 把 出生日期和结婚日期转换为日期类型
                        ldts -> ldts[0].until(ldts[1]).getYears()); // 计算张三的结婚年龄 ; // 计算张三的结婚年龄
        println(p);
    }

    /**
     * 
     */
    @Test
    public void iris() {
        try (final var excel = SimpleExcel.of("F:\\slicef\\desktop\\doc\\s\\iris.xlsx")) {
            final var dfm = excel.autoDetect(0).collect(DFrame.dfmclc2);

            for (final var key : "Sepal.Width,Sepal.Length,Petal.Width,Petal.Length".split(",")) {
                println(key);
                final var rng = dfm.colS(key, IRecord.obj2dbl()).collect(NVec.nveclc()).range();
                println(rng, NVec.of(10, i -> i).div(10 * rng.span()).add(rng._1));
                dfm.groupMapReduce(e -> Math.round(e.dbl(key)), e -> e.str("Species"), bb -> XVec.OF(bb).freq(),
                        IRecord::REC).forEach(tup -> {
                            println(tup);
                        });
            } // for

            final var rand = new Random();
            final var x = NVec.of(10000, i -> rand.nextInt(10));
            println(x.freq());
            println(IRecord.REC("x", x).llS2("x", e -> (Double) e).collect(XVec.xveclc()).freq());
        }

    }

    /**
     * 分箱
     */
    @Test
    public void bin() {
        final var bins = Range.of(1).binS(10).collect(XVec.xveclc());
        final var data = NVec.of(10000, i -> Math.random()) //
                .fmap(e -> bins.firstOf(rg -> rg.contains01(e))._1);
        final var freq = data.freq(IRecord::REC).sorted();
        println(freq, freq.arrayOf((Double[] e) -> NVec.of(e)).sum());
    }

    /**
     * 比较器
     */
    @Test
    public void compare() {
        final var a = Tuple2.TUP2((Integer) null, 1);
        final var b = Tuple2.TUP2(1, 0);
        final Comparator<Tuple2<Integer, Integer>> comparator = Tuple2.defaultComparator();
        println("cmp", comparator.compare(b, a));
    }

    @Test
    public void tomap() {
        final var rec = REC("1", REC(2, REC("3", REC("4", L(REC("name", "zhangsan"), REC("name", "lisi"))))));
        println(rec.toMap(true));
        println(rec.json());
    }
}
